package com.alex.doc.plugin;

import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.lang.jvm.annotation.JvmAnnotationAttribute;
import com.intellij.lang.jvm.annotation.JvmAnnotationAttributeValue;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

public class DocPlugin extends AnAction {

  private static final List<String> RequestMapping =
      Arrays.asList(
          "org.springframework.web.bind.annotation.RequestMapping",
          "org.springframework.web.bind.annotation.DeleteMapping",
          "org.springframework.web.bind.annotation.PatchMapping",
          "org.springframework.web.bind.annotation.PostMapping",
          "org.springframework.web.bind.annotation.PutMapping",
          "org.springframework.web.bind.annotation.GetMapping");

  private static final List<String> Controller =
      Arrays.asList(
          "org.springframework.web.bind.annotation.RestController",
          "org.springframework.stereotype.Controller");

  private static void extracted(PsiMethod method) {
    System.out.println("\n\t方法名称");
    System.out.println(method.getName());
    System.out.println("\n\t方法注释");
    System.out.println(method.getDocComment());
    System.out.println("\n\t注解");
    for (PsiAnnotation annotation : method.getAnnotations()) {
      System.out.println("\n\t名称");
      System.out.println(annotation.getQualifiedName());
      System.out.println("\n\tt注解属性");
      for (JvmAnnotationAttribute attribute : annotation.getAttributes()) {
        System.out.println(attribute.getAttributeName() + ":" + attribute.getAttributeValue());
      }
    }
  }

  private static String getAnnotationValue(JvmAnnotationAttribute jvmAnnotationAttribute) {
    if ((jvmAnnotationAttribute instanceof PsiNameValuePair) == false) {
      return null;
    }
    PsiNameValuePair pair = (PsiNameValuePair) jvmAnnotationAttribute;
    return pair.getLiteralValue();
  }

  @Override
  public void actionPerformed(AnActionEvent e) {
    Project project = e.getProject();
    PsiFile psiFile = e.getDataContext().getData(CommonDataKeys.PSI_FILE);
    VirtualFile virtualFile = psiFile.getVirtualFile();
    // 文件名称
    String fileName = virtualFile.getName();
    // 文件路径
    String filePath = virtualFile.getPath();
    // 弹框使用
    // Messages.showMessageDialog(project, fileName, filePath, Messages.getInformationIcon());
    processFile(project, psiFile);
  }

  /**
   * 解析文件
   *
   * @param project
   * @param file
   */
  private void processFile(Project project, PsiFile file) {
    List<PsiClass> classElements = getClasses(file);
    List<PsiElement> elements = new LinkedList<>(classElements);
    for (PsiClass classElement : classElements) {
      // 获取Method
      elements.addAll(PsiTreeUtil.getChildrenOfTypeAsList(classElement, PsiMethod.class));
      // 获取字段
      elements.addAll(PsiTreeUtil.getChildrenOfTypeAsList(classElement, PsiField.class));
    }
    for (PsiElement element : elements) {
      processElement(project, element);
    }
  }

  /**
   * 获取Class
   *
   * @param element
   * @return
   */
  private List<PsiClass> getClasses(PsiElement element) {
    List<PsiClass> classElements = PsiTreeUtil.getChildrenOfTypeAsList(element, PsiClass.class);
    List<PsiClass> elements = new LinkedList<>(classElements);
    for (PsiClass classElement : classElements) {
      elements.addAll(getClasses(classElement));
    }
    return elements;
  }

  /**
   * 解析具体元素的注解和值
   *
   * @param project
   * @param psiElement
   */
  protected void processElement(Project project, PsiElement psiElement) {
    System.out.println("==========================================Start");
    if (psiElement instanceof PsiClass) {
      PsiClass psiClass = (PsiClass) psiElement;
      PsiAnnotation psiAnnotation = AnnotationUtil.findAnnotation(psiClass, Controller);
      if (psiAnnotation == null) {
        return;
      }
      PsiAnnotation requestMapping = AnnotationUtil.findAnnotation(psiClass, RequestMapping);
      if (requestMapping != null) {
        System.out.println("RequestMapping:");
        for (JvmAnnotationAttribute attribute : requestMapping.getAttributes()) {
          JvmAnnotationAttributeValue attributeValue = attribute.getAttributeValue();
          System.out.println(attribute.getAttributeName() + ":" + getAnnotationValue(attribute));
        }
      }

    } else if (psiElement instanceof PsiMethod) {
      PsiMethod psiMethod = (PsiMethod) psiElement;
      PsiAnnotation requestMapping = AnnotationUtil.findAnnotation(psiMethod, RequestMapping);
      if (requestMapping != null) {
        System.out.println("RequestMapping:");
        for (JvmAnnotationAttribute attribute : requestMapping.getAttributes()) {
          System.out.println(attribute.getAttributeName() + ":" + getAnnotationValue(attribute));
        }
      }
    } else if (psiElement instanceof PsiField) {

    }
    System.out.println("==========================================End");
  }
}